package com.ht.api.db;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import com.ht.api.db.util.HtUtil;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;

/**
 * 数据实体类，对应数据库一行数据
 * @author asq
 * @createTime 2024年12月2日 23:44:44
 */
@Slf4j
@Getter
@Setter
@Accessors(chain = true)
public class Entity extends JSONObject implements Serializable {
	private static final long serialVersionUID = 1L;
	
    /** 数据库表名称 */
    private String table;
    /** 主键值 */
    private String mainId;
    
    /** 可以写入数据库的字段（用来解决有聚合函数的字段值翻倍的问题） */
    private List<String> funFields = new ArrayList<>();
    
    private Entity() {
    }

    private Entity(String table) {
    	setFromDb("table", table);
        this.table = table;
    }
    
    public String getTable() {
    	return table != null ? table : this.getStr("table");
    }
    
    public Entity setTable(String table) {
        this.table = table;
    	setFromDb("table", table);
    	return this;
    }
    
    /**
     * 创建一个实例
     * @param table
     * @return
     */
    public static Entity create() {
        return new Entity();
    }
    
    /**
     * 创建一个实例
     * @param table
     * @return
     */
    public static Entity create(String table) {
        return new Entity(table);
    }
    
    /**
     * 外部代码设置字段值时使用本方法<br>
     * 将字段值标记为需要更新
     */
    public Entity set(String key, Object value) {
        super.set(key, value);
        funFields.add(key);
        return this;
    }
    
    /**
     * 从数据库查询出来时，使用本方法赎值，目的是不标记字段需要更新
     * @param key
     * @param value
     * @return
     */
    public Entity setFromDb(String key, Object value) {
        super.set(key, value);
        return this;
    }

    /**
     * 设置主键值
     * @param mainId
     * @return
     */
    public Entity setMainId(Object mainId) {
        this.mainId = mainId.toString();
        return this;
    }

    /**
     * 获取主键值
     * @return
     */
    public String getMainId () {
        if (StrUtil.isBlank(mainId)) {
            if (StrUtil.isNotBlank(this.getStr("main_id"))) {
                this.mainId = this.getStr("main_id");
                return this.mainId;
            }
            
            if (StrUtil.isBlank(table)) {
            	table = this.getStr("table");
            }
            
            if (DbConfig.isNaturePrimary(table)) {
                List<String> primaryList = DbConfig.getPrimaryKeys(table);
                StringBuilder primaryKey = StrUtil.builder();
                for (String field : primaryList) {
                    if (StrUtil.isBlank(this.getStr(field))) {
                        log.info(this.toStringPretty());
                        throw new RuntimeException("异常 : 主键没有值 -> " + table);
                    }

                    primaryKey.append(this.getStr(field));
                }

                mainId = HtUtil.uniqueStrToNum(primaryKey.toString());
            } else {
                mainId = HtUtil.getId();
            }

        }

        this.set("main_id", this.mainId);
        return this.mainId;
    }
}
